package main

import (
	"fmt"
	"image/color"
	"math"
	"math/rand"
	"time"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/ebitenutil"
	"github.com/hajimehoshi/ebiten/v2/inpututil"
	"github.com/hajimehoshi/ebiten/v2/text"
	"github.com/hajimehoshi/ebiten/v2/vector"
	"golang.org/x/image/font"
	"golang.org/x/image/font/gofont/goregular"
	"golang.org/x/image/font/opentype"
)

// ======================
//
//	游戏常量定义
//
// ======================
const (
	screenWidth             = 1280
	screenHeight            = 720
	tileSize                = 40
	TowerTypeNone TowerType = iota

	// 游戏平衡参数
	initialGold       = 300
	initialPlayerHP   = 20
	towerCost         = 150
	towerRange        = 150
	towerDamage       = 25
	bulletSpeed       = 8
	towerCooldown     = 15 // 子弹冷却速度
	enemyBaseHP       = 30
	enemyHPWaveFactor = 20
	enemyBaseSpeed    = 1.5 // 敌人移动速度

	// 菜单相关常量
	menuWidth      = 200
	menuHeight     = 200
	menuX          = screenWidth - menuWidth
	menuY          = screenHeight - menuHeight
	menuButtonX    = screenWidth - 100
	menuButtonY    = screenHeight - 50
	menuButtonSize = 50
	towerIconSize  = 64

	// 血条相关常量
	healthBarWidth  = 20.0
	healthBarHeight = 3.0
	healthBarOffset = 15.0 // 血条与敌人的垂直间距
)

// 定义颜色变量
var (
	infoColor     = color.RGBA{255, 255, 255, 255} // 白色
	gameOverColor = color.RGBA{255, 0, 0, 255}     // 红色
)

// ======================
//
//	数据结构定义
//
// ======================
type Game struct {
	playerBaseHP      int             // 玩家基地生命值
	gold              int             // 当前金币
	wave              int             // 当前波次
	enemies           []*Enemy        // 敌人列表
	towers            []*Tower        // 防御塔列表
	bullets           []*Bullet       // 子弹列表
	path              []Point         // 敌人移动路径
	spawnTimer        time.Time       // 敌人生成计时器
	gameOver          bool            // 游戏是否结束
	selectedTowerType TowerType       // 当前选中的防御塔类型
	towerImages       []*ebiten.Image // 防御塔图片数组
	backgroundImage   *ebiten.Image   // 背景图片
	menu              *Menu           // 新增：菜单
	mouseX, mouseY    int             // 鼠标位置
	pathSpawnTimer    time.Time       // 新路线生成计时器
	waveInterval      time.Duration   // 新增：波次间隔时间
}

type Point struct{ X, Y float64 }

type Enemy struct {
	Pos       Point   // 当前位置
	PathIndex int     // 当前路径点索引
	HP        int     // 生命值
	MaxHP     int     // 最大生命值
	Type      string  // 敌人类型
	Speed     float64 // 移动速度
}

type Bullet struct {
	Start  Point     // 起始位置
	Target *Enemy    // 目标敌人
	Pos    Point     // 当前位置
	Speed  float64   // 飞行速度
	Damage int       // 伤害值
	Type   TowerType // 子弹类型
}

// ======================
//
//	初始化函数
//
// ======================
func NewGame() *Game {
	// 加载背景图片
	var err error
	backgroundImage, _, err := ebitenutil.NewImageFromFile("Snipaste_2024-11-04_20-42-36.png")
	if err != nil {
		panic(err)
	}
	// 初始化游戏
	g := &Game{
		playerBaseHP:      initialPlayerHP,
		gold:              initialGold,
		wave:              0,
		enemies:           make([]*Enemy, 0),
		towers:            make([]*Tower, 0),
		bullets:           make([]*Bullet, 0),
		path:              generatePath(),
		spawnTimer:        time.Now(),
		gameOver:          false,
		selectedTowerType: TowerTypeNone,
		towerImages:       make([]*ebiten.Image, 0),
		backgroundImage:   backgroundImage,                              // 这里需要根据实际情况加载背景图片
		menu:              NewMenu(menuX, menuY, menuWidth, menuHeight), // 这里需要根据实际情况初始化菜单
		mouseX:            0,
		mouseY:            0,
		pathSpawnTimer:    time.Now(),
		waveInterval:      10 * time.Second, // 假设波次间隔为10秒
	}
	return g
}

// 生成地图路径（带分支的直角折线路径）
func generatePath() []Point {
	// 定义公共部分路径
	commonPath := []Point{
		{X: 0, Y: 360},
		{X: 320, Y: 360},
	}

	// 定义分支路径
	branch1 := []Point{
		{X: 320, Y: 160},
		{X: 640, Y: 160},
		{X: 640, Y: 560},
		{X: 960, Y: 560},
		{X: 1280, Y: 560},
	}
	branch2 := []Point{
		{X: 320, Y: 560},
		{X: 640, Y: 560},
		{X: 640, Y: 160},
		{X: 960, Y: 160},
		{X: 1280, Y: 160},
	}

	// 随机选择分支
	rand.Seed(time.Now().UnixNano())
	if rand.Intn(2) == 0 {
		commonPath = append(commonPath, branch1...)
	} else {
		commonPath = append(commonPath, branch2...)
	}

	return commonPath
}

// ======================
//
//	主游戏循环
//
// ======================
func (g *Game) Update() error {
	if g.gameOver {
		return nil
	}

	// 检查新路线生成计时器是否结束
	if time.Now().After(g.pathSpawnTimer) {
		// 生成新路线
		g.path = generatePath()
		// 生成敌人
		g.spawnWave()
		// 重置新路线生成计时器，30秒后再次生成新路线
		g.pathSpawnTimer = time.Now().Add(30 * time.Second)
	}

	// 更新鼠标位置
	g.mouseX, g.mouseY = ebiten.CursorPosition()

	g.handleInput()   // 处理玩家输入
	g.updateEnemies() // 更新敌人状态
	g.updateTowers()  // 更新塔状态
	g.updateBullets() // 更新子弹状态
	g.spawnWave()     // 生成敌人波次

	// 游戏失败判断
	if g.playerBaseHP <= 0 {
		g.gameOver = true
	}
	return nil
}

// ======================
//
//	输入处理
//
// ======================
func (g *Game) handleInput() {
	// 处理菜单点击事件
	if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
		x, y := ebiten.CursorPosition()
		// 检查点击是否在菜单图标区域
		if x >= menuX+20 && x < menuX+20+towerIconSize {
			if y >= menuY+20 && y < menuY+20+towerIconSize {
				g.selectedTowerType = TowerType1
			} else if y >= menuY+20+towerIconSize && y < menuY+20+2*towerIconSize {
				g.selectedTowerType = TowerType2
			} else if y >= menuY+20+2*towerIconSize && y < menuY+20+3*towerIconSize {
				g.selectedTowerType = TowerType3
			}
		} else if g.selectedTowerType != 0 {
			// 放置防御塔
			if g.canPlaceTower(x, y) && g.gold >= towerCost {
				tower := NewTower(Point{X: float64(x), Y: float64(y)}, g.selectedTowerType)
				g.towers = append(g.towers, tower)
				g.gold -= towerCost
			}
		}
	}
}

// ======================
//
//	敌人系统
//
// ======================
func (g *Game) spawnWave() {
	// 检查是否达到波次间隔时间
	if time.Since(g.spawnTimer) < g.waveInterval {
		return
	}
	g.wave++
	// 生成敌人的逻辑
	enemyCount := g.wave * 2 // 每波敌人数量随波次增加
	for i := 0; i < enemyCount; i++ {
		enemyHP := enemyBaseHP + g.wave*enemyHPWaveFactor
		enemy := &Enemy{
			Pos:       g.path[0],
			PathIndex: 0,
			HP:        enemyHP,
			MaxHP:     enemyHP,
			Type:      "normal",
			Speed:     enemyBaseSpeed,
		}
		g.enemies = append(g.enemies, enemy)
	}
	// 更新计时器
	g.spawnTimer = time.Now()
}

// 更新敌人位置和状态
func (g *Game) updateEnemies() {
	for i := 0; i < len(g.enemies); i++ {
		e := g.enemies[i]
		// 检查敌人是否死亡
		if e.HP <= 0 {
			g.gold += 30 // 击杀奖励
			g.enemies = append(g.enemies[:i], g.enemies[i+1:]...)
			i-- // 调整索引
			continue
		}

		target := g.path[e.PathIndex+1]

		// 计算移动方向和距离
		dx := target.X - e.Pos.X
		dy := target.Y - e.Pos.Y
		distance := math.Sqrt(dx*dx + dy*dy)

		if distance < e.Speed { // 到达路径点
			e.Pos = target
			e.PathIndex++
			if e.PathIndex >= len(g.path)-1 { // 到达终点
				g.playerBaseHP -= 2
				g.enemies = append(g.enemies[:i], g.enemies[i+1:]...)
				i-- // 调整索引
			}
		} else { // 向路径点移动
			e.Pos.X += dx / distance * e.Speed
			e.Pos.Y += dy / distance * e.Speed
		}
	}
}

// ======================
//
//	防御塔系统
//
// ======================
func (g *Game) updateTowers() {
	for _, t := range g.towers {
		t.Update(g)
	}
}

// ======================
//
//	子弹系统
//
// ======================
func (g *Game) updateBullets() {
	for i := 0; i < len(g.bullets); i++ {
		b := g.bullets[i]
		if b.Target == nil || b.Target.HP <= 0 { // 增强判断
			g.bullets = append(g.bullets[:i], g.bullets[i+1:]...)
			i--
			continue
		}

		// 计算子弹移动
		dx := b.Target.Pos.X - b.Pos.X
		dy := b.Target.Pos.Y - b.Pos.Y
		dist := math.Sqrt(dx*dx + dy*dy)

		if dist < b.Speed { // 命中目标
			b.Target.HP -= b.Damage
			if b.Type == TowerType2 { // 远程防御塔的范围伤害
				for _, e := range g.enemies {
					if distance(b.Target.Pos, e.Pos) <= 50 { // 范围伤害半径
						e.HP -= b.Damage / 2 // 范围伤害减半
					}
				}
			}
			g.bullets = append(g.bullets[:i], g.bullets[i+1:]...)
			i--
		} else { // 继续移动
			b.Pos.X += dx / dist * b.Speed
			b.Pos.Y += dy / dist * b.Speed
		}
	}
}

// ======================
//
//	辅助函数
//
// ======================
// 计算两点间距离
func distance(a, b Point) float64 {
	dx := a.X - b.X
	dy := a.Y - b.Y
	return math.Sqrt(dx*dx + dy*dy)
}

// 寻找攻击目标（简单实现：选择第一个进入范围的敌人）
func (g *Game) findTarget(t *Tower) *Enemy {
	for _, e := range g.enemies {
		if distance(t.Pos, e.Pos) <= t.Range {
			return e
		}
	}
	return nil
}

// 塔防放置检测
func (g *Game) canPlaceTower(x, y int) bool {

	// 1. 检查是否超出屏幕范围
	if x < 0 || x >= screenWidth || y < 0 || y >= screenHeight {
		return false
	}
	// 2. 检查是否与其他塔重叠
	for _, t := range g.towers {
		dx := t.Pos.X - float64(x)
		dy := t.Pos.Y - float64(y)
		distance := math.Sqrt(dx*dx + dy*dy)
		if distance < tileSize { // 塔之间的最小间距
			return false
		}
	}
	// 3. 检查是否在地图边缘（可选）
	if x < tileSize || x > screenWidth-tileSize || y < tileSize || y > screenHeight-tileSize {
		return false
	}
	return true
}

// ======================
//
//	绘图系统
//
// ======================
func (g *Game) Draw(screen *ebiten.Image) {

	// 绘制背景图片
	if g.backgroundImage != nil {
		opts := &ebiten.DrawImageOptions{}
		sx := float64(screenWidth) / float64(g.backgroundImage.Bounds().Dx())
		sy := float64(screenHeight) / float64(g.backgroundImage.Bounds().Dy())
		opts.GeoM.Scale(sx, sy)
		screen.DrawImage(g.backgroundImage, opts)
	}

	// 绘制其他元素，如敌人、防御塔等
	for _, enemy := range g.enemies {
		drawEnemy(screen, enemy)
	}
	for _, tower := range g.towers {
		tower.Draw(screen)
	}
	for _, bullet := range g.bullets {
		drawBullet(screen, bullet)
	}
	// 绘制放置检查圈
	if g.selectedTowerType != TowerTypeNone {
		checkCircleColor := color.RGBA{0, 255, 0, 128} // 默认绿色
		if !g.canPlaceTower(g.mouseX, g.mouseY) {
			checkCircleColor = color.RGBA{255, 0, 0, 128} // 不可放置时为红色
		}
		vector.StrokeCircle(screen, float32(g.mouseX), float32(g.mouseY), float32(towerRange), 2, checkCircleColor, false)
	}
	// 绘制菜单
	g.menu.Draw(screen, g.selectedTowerType)

	// 绘制网格（调试用）
	drawGrid(screen)

	// 绘制路径
	drawPath(screen, g.path)

	// 绘制UI信息
	drawUI(screen, g)
}

// 绘制网格（调试用）
func drawGrid(screen *ebiten.Image) {
	for x := 0; x < screenWidth; x += tileSize {
		vector.StrokeLine(screen, float32(x), 0, float32(x), float32(screenHeight), 1, color.RGBA{128, 128, 128, 128}, false)
	}
	for y := 0; y < screenHeight; y += tileSize {
		vector.StrokeLine(screen, 0, float32(y), float32(screenWidth), float32(y), 1, color.RGBA{128, 128, 128, 128}, false)
	}
}

// 绘制路径（绿色线条）
func drawPath(screen *ebiten.Image, path []Point) {
	for i := 0; i < len(path)-1; i++ {
		vector.StrokeLine(screen, float32(path[i].X), float32(path[i].Y), float32(path[i+1].X), float32(path[i+1].Y), 3, color.RGBA{0, 255, 0, 255}, false)
	}
}

// 绘制防御塔（蓝色圆形）
func drawTower(screen *ebiten.Image, t *Tower) {
	// 将塔的位置转换为合适的类型（如果需要）
	x := int(t.Pos.X)
	y := int(t.Pos.Y)
	// 定义颜色为蓝色
	towerColor := color.RGBA{B: 255, A: 255}
	// 绘制圆形表示塔，半径增大到20
	vector.DrawFilledCircle(screen, float32(x), float32(y), 20, towerColor, false)
	// 绘制攻击范围指示圈
	rangeColor := color.RGBA{B: 255, A: 64}
	vector.StrokeCircle(screen, float32(x), float32(y), float32(t.Range), 2, rangeColor, false)
}

// 绘制敌人（红色圆形）
func drawEnemy(screen *ebiten.Image, e *Enemy) {
	// 绘制敌人本体
	enemyColor := color.RGBA{178, 3, 3, 255}
	vector.DrawFilledCircle(screen, float32(e.Pos.X), float32(e.Pos.Y), 10, enemyColor, true)

	// 绘制血条背景
	healthBarX := float32(e.Pos.X) - healthBarWidth/2
	healthBarY := float32(e.Pos.Y) - healthBarOffset // 在敌人上方显示

	// 血条背景（剩余生命值）
	DrawFilledRect(screen, healthBarX, healthBarY, healthBarWidth, healthBarHeight, color.RGBA{50, 0, 0, 200})

	// 当前生命值比例
	healthRatio := float32(e.HP) / float32(e.MaxHP)
	if healthRatio < 0 {
		healthRatio = 0
	}

	// 当前生命值条
	DrawFilledRect(screen, healthBarX, healthBarY, healthBarWidth*healthRatio, healthBarHeight, color.RGBA{200, 30, 30, 255})
}

func DrawFilledRect(screen *ebiten.Image, x, y, width, height float32, clr color.Color) {
	// 通过绘制四个边实现填充效果
	vector.StrokeRect(screen, x, y, width, height, 1, clr, true)
	vector.StrokeRect(screen, x+0.5, y+0.5, width-1, height-1, 1, clr, true)
	vector.StrokeRect(screen, x+1, y+1, width-2, height-2, 1, clr, true)
	vector.StrokeRect(screen, x+1.5, y+1.5, width-3, height-3, 1, clr, true)
}

// 绘制子弹（小红点）
func drawBullet(screen *ebiten.Image, b *Bullet) {
	vector.DrawFilledCircle(screen, float32(b.Pos.X), float32(b.Pos.Y), 5, color.RGBA{255, 4, 0, 255}, true)
}

// 加载字体
func loadFont() font.Face {
	// 加载内置的 Go 字体
	ttf, err := opentype.Parse(goregular.TTF)
	if err != nil {
		panic(err)
	}

	// 创建字体
	fontFace, err := opentype.NewFace(ttf, &opentype.FaceOptions{
		Size:    24, // 字体大小
		DPI:     72, // DPI
		Hinting: font.HintingFull,
	})
	if err != nil {
		panic(err)
	}

	return fontFace
}

// 绘制UI信息
func drawUI(screen *ebiten.Image, g *Game) {
	// 设置字体颜色为白色
	fontColor := color.White
	// 加载字体
	font := loadFont()

	// 绘制金币信息
	goldText := fmt.Sprintf("Gold: %d", g.gold)
	text.Draw(screen, goldText, font, 20, 30, fontColor)

	// 绘制波次信息
	waveText := fmt.Sprintf("Wave: %d", g.wave)
	text.Draw(screen, waveText, font, 20, 60, fontColor)

	// 绘制玩家基地生命值
	hpText := fmt.Sprintf("Base HP: %d", g.playerBaseHP)
	text.Draw(screen, hpText, font, 20, 90, fontColor)

	// 绘制路线倒计时
	remainingTime := time.Until(g.pathSpawnTimer)
	if remainingTime > 0 {
		pathTimerText := fmt.Sprintf("Next Path in: %.0f seconds", remainingTime.Seconds())
		text.Draw(screen, pathTimerText, font, 20, 120, fontColor)
	} else {
		pathUpdateText := "Updating Path..."
		text.Draw(screen, pathUpdateText, font, 20, 120, fontColor)
	}

	// 绘制波次倒计时
	const countdownDuration = 10 * time.Second // 波次倒计时总时长
	waveRemainingTime := countdownDuration - time.Since(g.spawnTimer)
	if waveRemainingTime > 0 {
		waveTimerText := fmt.Sprintf("Next Wave in: %.0f seconds", waveRemainingTime.Seconds())
		text.Draw(screen, waveTimerText, font, 20, 150, fontColor)
	} else {
		waveUpdateText := "Updating Wave..."
		text.Draw(screen, waveUpdateText, font, 20, 150, fontColor)
	}
}

// ======================
//
//	窗口设置
//
// ======================
func (g *Game) Layout(_, _ int) (int, int) {
	return screenWidth, screenHeight
}

func main() {
	ebiten.SetWindowSize(screenWidth, screenHeight)
	ebiten.SetWindowTitle("游戏")
	if err := ebiten.RunGame(NewGame()); err != nil {
		panic(err)
	}
}
